﻿#include "VertexArray.h"

// lib
#include <glad/glad.h>

VertexArray::VertexArray()
{
  glGenVertexArrays(1, &m_id);
  
  Bind();
  m_vertexBuffer = CreateRef<VertexBuffer>();
  Unbind();
}

VertexArray::~VertexArray()
{
  if (IsValid())
    glDeleteVertexArrays(1, &m_id);
}

void VertexArray::Bind() const
{
  glBindVertexArray(m_id);
  if (m_vertexBuffer)
    m_vertexBuffer->Bind();
  if (m_indexBuffer)
    m_indexBuffer->Bind();
}

void VertexArray::Unbind() const
{
  glBindVertexArray(0);
}

void VertexArray::DrawIndexed(int32_t type) const
{
  assert(m_indexBuffer != nullptr);

  Bind();
  glDrawElements(type, m_indexBuffer->GetSize(), m_indexBuffer->GetType(), nullptr);
  Unbind();
}

void VertexArray::DrawVertex(int32_t type) const
{
  DrawVertexSub(m_vertexBuffer->GetSize(), 0, type);
}

void VertexArray::DrawVertexSub(int32_t size, int32_t startOffset, int32_t type) const
{
  if (!IsValid())
    return;
  assert(m_indexBuffer == nullptr);

  Bind();
  glDrawArrays(type, startOffset, size);
  Unbind();
}

void VertexArray::AddVertexAttributes(const std::vector<VertexAttribute> &vector, int32_t defaultVertexSize)
{
  Bind();

  size_t offset = 0;

  for (size_t i = 0; i < vector.size(); i++)
  {
    const auto &[componentCount, type, shouldBeNormalized, vertexSize] = vector[i];
    const auto normalize = shouldBeNormalized ? GL_TRUE : GL_FALSE;
    const auto stride = vertexSize ? vertexSize : defaultVertexSize;

    switch (type)
    {
    case VertexAttribute::UShort:
      glVertexAttribIPointer(i, componentCount, type, stride, reinterpret_cast<void *>(offset));
      offset += componentCount * sizeof(short);
      break;
    case VertexAttribute::Int:
    case VertexAttribute::UInt:
      glVertexAttribIPointer(i, componentCount, type, stride, reinterpret_cast<void *>(offset));
      offset += componentCount * sizeof(int);
      break;
    case VertexAttribute::Byte:
      glVertexAttribIPointer(i, componentCount, type, stride, reinterpret_cast<void *>(offset));
      offset += componentCount * sizeof(char);
      break;
    case VertexAttribute::Float:
      glVertexAttribPointer(i, componentCount, type, normalize, stride, reinterpret_cast<void *>(offset));
      offset += componentCount * sizeof(float);
      break;
    }
    glEnableVertexAttribArray(i);
  }
  Unbind();
}